/**************************************************************************************************
	$Header: /pub/cvsroot/mydns/src/mydns/named.h,v 1.18 2002/08/31 08:08:00 bboy Exp $

	Copyright (C) 2002  Don Moore <bboy@bboy.net>

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at Your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
**************************************************************************************************/

#ifndef _MYNAMED_H
#define _MYNAMED_H

#include "mydnsutil.h"
#include "header.h"
#include "mydns.h"
#include "cache.h"

#if HAVE_SYS_RESOURCE_H
#	include <sys/resource.h>
#endif

#if HAVE_SYS_WAIT_H
#	include <sys/wait.h>
#endif

#if HAVE_NETDB_H
#	include <netdb.h>
#endif


/* The alarm function runs every ALARM_INTERVAL seconds */
#define	ALARM_INTERVAL		5
#define	DNS_MAXPACKETLEN	DNS_MAXPACKETLEN_UDP
#define	MAX_CNAME_LEVEL	6

/* Maximum CNAME recursion depth */
#define	DNS_MAX_CNAME_RECURSION	25

/* Size of reply header data; that's id + DNS_HEADER + qdcount + ancount + nscount + arcount */
#define	DNS_HEADERSIZE		(SIZE16 * 6)


/* Information about the PTR suffix */
#define	PTR_SUFFIX		".in-addr.arpa."
#define	PTR_SUFFIX_LEN	14						/* strlen(".in-addr.arpa.") */

#define SQLESC(s,d) { \
		u_char *rv = alloca(strlen((s))*2+1); \
		if (!rv) Err("alloca"); \
		mysql_real_escape_string(mysql, rv, s, strlen((s))); \
		d = rv; \
	}

/* This is the header offset at the start of most reply functions.
	The extra SIZE16 at the end is the RDLENGTH field in the RR's header. */
#define CUROFFSET(t) (DNS_HEADERSIZE + (t)->qdlen + (t)->rdlen + SIZE16)


/* Task status flags */
typedef enum _taskstat_t
{
	NEED_READ,									/* We need to read the question */
	NEED_ANSWER,								/* We need to find the answer */
	NEED_WRITE									/* We need to write the answer */
} taskstat_t;


/* Sections in reply */
typedef enum _datasection_t
{
	ANSWER, AUTHORITY, ADDITIONAL
} datasection_t;


/* RR: A single resource record (of any supported type) */
typedef struct _named_rr
{
	dns_rrtype_t rrtype;						/* Record type (what table this data came from) */
	u_int32_t	id;							/* ID associated with RR */
	u_char		name[DNS_MAXNAMELEN];	/* Name to send with reply */
	off_t			offset;						/* The offset within the reply data (t->rdata) */
	size_t		length;						/* The length of data within the reply */
	int			sort;							/* Sort order */
	unsigned int lb_low, lb_high;			/* High/low values for load balancing (ugh) */
	void			*rr;							/* The RR data */

	struct _named_rr *next;					/* Pointer to the next item */
} RR;

/* RRLIST: A list of resource records */
typedef struct _named_rrlist
{
	size_t size;								/* Count of records */

	int addresses;								/* Number of A or AAAA records */
	int highest_addr_aux;					/* Highest "aux" value from A or AAAA */

	int mxrecords;								/* Number of MX records */

	RR *head;									/* Head of list */
	RR *tail;									/* Tail of list */
} RRLIST;


/* TASK: DNS query task */
typedef struct _named_task
{
	u_int64_t	internal_id;									/* Internal task ID */
	taskstat_t	status;											/* Current status of query */
	int			fd;												/* Socket FD */
	time_t		timeout;											/* Time task expires (timeout) */
	int			protocol;										/* Type of socket (SOCK_DGRAM/SOCK_STREAM) */
	struct sockaddr_in addr;									/* Address of client */

	/* I/O information for TCP queries */
	size_t		len;												/* Query length */
	u_char		*query;											/* Query data */
	size_t		offset;											/* Current offset */
	int			len_written;									/* Have we written length octets? */

	/* Query information */
	u_int32_t	minimum_ttl;									/* Minimum TTL for current zone */
	u_int16_t	id;												/* Query ID */
	DNS_HEADER  hdr;												/* Header */
	dns_class_t qclass;											/* Query class */
	dns_qtype_t	qtype;											/* Query type */
	u_char		qname[DNS_MAXNAMELEN];						/* Query name object */
	enum task_error_t reason;									/* Further explanation of the error */

	u_int32_t	Cnames[MAX_CNAME_LEVEL];					/* Array of CNAMEs found */

	u_char		*qd;												/* Question section data */
	size_t		qdlen;											/* Size of question section */
	u_int16_t	qdcount;											/* "qdcount", from header field */

	int			no_markers;										/* Do not use markers? */
	u_char		**Names;											/* Names stored in reply */
	u_int			*Offsets;										/* Offsets for names */
	u_int			numNames;										/* Number of names in the list */

	RRLIST		an, ns, ar;										/* RR's for ANSWER, AUTHORITY, ADDITIONAL */

	u_char		*rdata;											/* Header portion of reply */
	size_t		rdlen;											/* Length of `rdata' */

	u_char		*reply;											/* Total constructed reply data */
	size_t		replylen;										/* Length of `reply' */

	struct _named_task *prev, *next;							/* Pointers to previous/next rec in queue */
} TASK;


/* Queue structure for TASK records (really not a queue, but a list) */
typedef struct _named_queue
{
	size_t size;													/* Number of elements in queue */
	TASK	*head;													/* Pointer to first element in list */
	TASK	*tail;													/* Pointer to last element in list */
} QUEUE;


typedef struct _serverstatus									/* Server status information */
{
	time_t		start_time;	 									/* Time server started */
	u_int64_t	udp_requests, tcp_requests;				/* Total # of requests handled */
	u_int64_t	timedout;	 									/* Number of requests that timed out */
	u_int64_t	success;		 									/* Number of successful requests */
	u_int64_t	fail;			 									/* Number of failed requests */
} SERVERSTATUS;

extern SERVERSTATUS Status;



/* Global variables */
extern CONF		*Conf;											/* Config file data */
extern MYSQL	*mysql;											/* MySQL database connection */
extern QUEUE	*Tasks;											/* Task queue */
extern CACHE	*Cache;											/* Zone cache */
extern time_t	current_time;									/* Current time */
extern time_t	task_timeout;									/* Task timeout */
extern int		axfr_enabled;									/* Allow AXFR? */
extern int		tcp_enabled;									/* Enable TCP? */

extern u_int32_t answer_then_quit;							/* Answer this many queries then quit */


extern void axfr(TASK *);																					/* axfr.c */

extern void load_config(void);																			/* conf.c */
extern void dump_config(void);																			/* conf.c */
extern void conf_set_logging(void);																		/* conf.c */
extern void check_config_file_perms(void);															/* conf.c */

extern MYDNS_SOA	*find_soa(TASK *, u_char *, u_char *);											/* data.c */
extern MYDNS_PTR	*find_ptr(TASK *, u_char *);														/* data.c */
extern MYDNS_RR	*find_rr(TASK *, u_int32_t, unsigned char *, dns_qtype_t, unsigned char *);	/* data.c */

extern void db_connect(void);																				/* db.c */
extern void db_output_create_tables(void);															/* db.c */
extern void db_verify_tables(void);																		/* db.c */

extern void name_remember(TASK *, u_char *, u_int);												/* encode.c */
extern void name_forget(TASK *);																			/* encode.c */
extern u_int name_find(TASK *, u_char *);																/* encode.c */
extern u_char *name_unencode(u_char *, size_t, u_char *, u_char *, size_t);				/* encode.c */
extern int	name_encode(TASK *, u_char *, u_char *, u_int);										/* encode.c */

#define dnserror(task,rcode,reason)	_dnserror_internal((task),(rcode),(reason),__FILE__,__LINE__)
extern int _dnserror_internal(TASK *, dns_rcode_t, enum task_error_t,
										const char *, unsigned int);										/* error.c */

extern char *err_reason_str(enum task_error_t);														/* error.c */

extern QUEUE *queue_init(void);																			/* queue.c */
extern void	enqueue(QUEUE *, TASK *);																	/* queue.c */
extern void	dequeue(QUEUE *, TASK *, int);															/* queue.c */

extern void reply_init(TASK *);																			/* reply.c */
extern void build_reply(TASK *, int);																	/* reply.c */

extern int resolve(TASK *, datasection_t, dns_qtype_t, u_char *, int);						/* resolve.c */

extern void rrlist_add(TASK *, datasection_t, dns_rrtype_t, void *, u_char *);			/* rr.c */
extern void rrlist_free(RRLIST *);																		/* rr.c */

extern void sort_addresses(TASK *, RRLIST *);														/* sort.c */
extern void sort_mx(TASK *, RRLIST *);																	/* sort.c */

extern void task_init_header(TASK *);																	/* task.c */
extern char	*desctask(TASK *);																			/* task.c */
extern TASK *task_init(taskstat_t, int, int, struct sockaddr_in *);							/* task.c */
extern void task_free(TASK *);																			/* task.c */
extern void task_build_reply(TASK *);																	/* task.c */
extern void task_output_info(TASK *);																	/* task.c */
extern TASK *task_process(TASK *);																		/* task.c */

extern int	accept_tcp_query(int);																		/* tcp.c */
extern int	read_tcp_query(TASK *);																		/* tcp.c */
extern int	write_tcp_reply(TASK *);																	/* tcp.c */

extern int	read_udp_query(int);																			/* udp.c */
extern int	write_udp_reply(TASK *);																	/* udp.c */

#endif /* _MYNAMED_H */

/* vi:set ts=3: */
